import React, { ChangeEvent, JSX } from 'react';
import moment from 'moment';
import { Box, IconButton, Button, TableContainer, Table, TableHead, TableRow, Checkbox, TableBody, TableFooter } from '@mui/material';
import { useAppSelector, useAppDispatch } from '../../actions/hooks';
import { NulHeaderTableCell, NulTableCell } from '../../components/NulHeaderTable';
import { removeElementFromArray } from '../../util/Arrays';
import { SelectHistoryEntry, fetchAllSelectHistory, fetchSelectHistoryDetail, selectHistoryActions, selectHistoryDetail, selectHistoryDetailLoaded, selectHistoryDownload, selectHistoryEntries, selectHistoryEntriesLoaded } from '../../actions/SelectHistory';
import { ReactComponent as CreateIcon } from '../../assets/create.svg';
import { analyzeActions, analyzeImage, fetchAllModels, selectAnalyzeModelLoaded, selectAnalyzeModels, selectAnalyzeResult, selectAnalyzeResultLoaded, selectAnalyzeSelectedModelId } from '../../actions/Analyze';
import { AlertBox } from '../../components/AlertBox';
import { AnalyzeResult } from '../AnalyzeDialog/AnalyzeResult';
import { AnalyzeHistory } from '../AnalyzeDialog/AnalyzeHistory';
import { DateField } from '@mui/x-date-pickers';
import AutorenewIcon from '@mui/icons-material/Autorenew';
import VisibilityIcon from '@mui/icons-material/Visibility';
import DownloadIcon from '@mui/icons-material/Download';
import SwitchModelDialog from '../AnalyzeDialog/SwitchModel';
import '@fontsource/open-sans';
import { transformAnalyzeResult } from '../../util/TextTransform';


function AnalyzeImage(): JSX.Element {

  const dispatch = useAppDispatch();

  const historyEntriesLoaded = useAppSelector(selectHistoryEntriesLoaded);
  const historyEntries = useAppSelector(selectHistoryEntries);
  const detailLoaded = useAppSelector(selectHistoryDetailLoaded);
  const detail = useAppSelector(selectHistoryDetail);
  const download = useAppSelector(selectHistoryDownload);
  const resulted = useAppSelector(selectAnalyzeResultLoaded);
  const result = useAppSelector(selectAnalyzeResult);
  const selectedModelId = useAppSelector(selectAnalyzeSelectedModelId);
  const modelLoaded = useAppSelector(selectAnalyzeModelLoaded);
  const models = useAppSelector(selectAnalyzeModels);


  const [checkedIdList, setCheckedIdList] = React.useState<number[]>([]);
  const [resultOpen, setResultOpen] = React.useState<boolean>(false);
  const [openSwitchModel, setOpenSwitchModel] = React.useState<boolean>(false);
  const [startDate, setStartDate] = React.useState<moment.Moment | null>(null);
  const [endDate, setEndDate] = React.useState<moment.Moment | null>(null);
  const [openAlert, setOpenAlert] = React.useState(false);
  const [filteredHistoryEntries, setFilteredHistoryEntries] = React.useState<SelectHistoryEntry[]>([]);
  const [file, setFile] = React.useState<File | undefined>(undefined);

  const inputRef = React.useRef<HTMLInputElement>(null);

  React.useEffect(() => {
    if (resulted && !download) {
      setResultOpen(true);
      dispatch(fetchAllSelectHistory());
    }
  }, [resulted, download, dispatch]);

  React.useEffect(() => {
    if (detail !== undefined && download) {
      const binaryString = window.atob(detail.data);
      const bytes = new Uint8Array(binaryString.length);

      for (let i = 0; i < binaryString.length; i++) {
        bytes[i] = binaryString.charCodeAt(i);
      }

      const buffer = new Uint8Array(bytes.buffer);
      const url: string = window.URL.createObjectURL(new Blob([buffer]));

      const a = document.createElement('a');
      a.hidden = true;
      a.href = url;
      a.download = detail.hash + '.dcm';
      a.click();
      a.remove();
      window.URL.revokeObjectURL(url);

      dispatch(selectHistoryActions.clearDetail());
    }
  }, [detail, download, dispatch]);

  React.useEffect(() => {
    if (!historyEntriesLoaded) {
      dispatch(fetchAllSelectHistory());
    }
    if (!modelLoaded) {
      dispatch(fetchAllModels());
    }
  });

  React.useEffect(() => {
    if (historyEntries !== undefined) {
      let filtered: SelectHistoryEntry[] = historyEntries;
      if ((startDate !== null && startDate.isValid()) && (endDate !== null && endDate.isValid())) {
        filtered = historyEntries.filter(val => {
          const time = moment(val.time, true);
          return time >= startDate && time <= endDate.clone().add(1, 'days').startOf('day');
        });
      }
      else if (!(startDate !== null && startDate.isValid()) && (endDate !== null && endDate.isValid())) {
        filtered = historyEntries.filter(val => {
          const time = moment(val.time, true);
          return time <= endDate.clone().add(1, 'days').startOf('day');
        });
      }
      else if ((startDate !== null && startDate.isValid()) && !(endDate !== null && endDate.isValid())) {
        filtered = historyEntries.filter(val => {
          const time = moment(val.time, true);
          return time >= startDate;
        });
      }
      setFilteredHistoryEntries(filtered);
      setCheckedIdList([]);
    }
  }, [historyEntries, startDate, endDate]);

  const handleFileUpload = (event: ChangeEvent<HTMLInputElement>) => {
    if (event.target.files === null) {
      return;
    }
    const file = event.target.files[0];
    setFile(file);
    const reader = new FileReader();
    reader.onload = (e: ProgressEvent<FileReader>) => {
      const buffer = e.target?.result as string;
      dispatch(analyzeImage({ 'image': buffer, 'model': selectedModelId }));
    }
    if (file) {
      reader.readAsDataURL(file);
    }
  };

  const handleViewHistory = (row: SelectHistoryEntry) => {
    dispatch(fetchSelectHistoryDetail({ id: row.id, download: false }));
  };

  const handleDownload = (row: SelectHistoryEntry) => {
    dispatch(fetchSelectHistoryDetail({ id: row.id, download: true }));
  };

  const headerChecked: boolean = checkedIdList.length !== 0 && checkedIdList.length === historyEntries.length;
  const headerIndeterminate: boolean = checkedIdList.length !== 0 && checkedIdList.length < historyEntries.length;

  return (
    <>
      <Box sx={{ padding: '30px 30px 30px 30px', flex: 'none', flexGrow: 1 }}>
        <Box sx={{
          fontFamily: 'Open Sans',
          fontStyle: 'normal',
          fontWeight: 600,
          fontSize: '22px',
          lineHeight: '125%',
          display: 'flex',
          flexDirection: 'row'
        }}>
          <Box>
            Analyze Image
          </Box>
          <Button
            startIcon={<AutorenewIcon />} sx={{ marginLeft: '10px', textTransform: 'none' }}
            onClick={() => { setOpenSwitchModel(true); }}
          >
            Model
          </Button>
        </Box>
        <Box sx={{
          marginTop: '20px', width: '100%', height: '40px', display: 'flex',
          flexDirection: 'row', justifyContent: 'space-between'
        }}>
          <Box sx={{ width: '456px', display: 'flex', flexDirection: 'row' }}>
            <DateField size='small' format='YYYY-MM-DD' value={startDate} onChange={(newValue) => {
              setStartDate(newValue);
            }} />
            <Box paddingLeft='10px' paddingRight='10px' lineHeight='40px' fontSize='16px' color='#606060'>—</Box>
            <DateField size='small' format='YYYY-MM-DD' value={endDate} onChange={(newValue) => {
              setEndDate(newValue);
            }} />
          </Box>
          <Box sx={{
            flex: 'none',
            order: 1,
            flexGrow: 0
          }}>
            <Button
              variant="contained"
              disableElevation
              startIcon={<CreateIcon />}
              onClick={() => {
                inputRef?.current?.click();
              }}
              sx={{
                height: '40px',
                textTransform: 'none'
              }}
            >
              Upload
              <input type='file' ref={inputRef} hidden aria-label='upload-image' onChange={handleFileUpload} />
            </Button>
          </Box>
        </Box>
        <Box sx={{
          marginTop: '20px',
          width: '100%'
        }}>
          <TableContainer
            sx={{
              width: '100%'
            }}
          >
            <Table
              stickyHeader
              sx={{
                border: '1px solid #DFE4E8',
                borderRadius: '8px',
                fontFamily: 'Open Sans',
                fontStyle: 'normal',
              }}
            >
              <TableHead sx={{ border: '8px 8px 0px 0px' }}>
                <TableRow sx={{
                  height: '42px',
                  padding: 0,
                  width: '100%',
                  display: 'flex',
                  alignItems: 'center',
                  backgroundColor: '#F1F3F5',
                  borderTopLeftRadius: '8px',
                  borderTopRightRadius: '8px'
                }}>
                  <Box sx={{ height: '100%' }}>
                    <NulHeaderTableCell
                      sx={{
                        width: '62px',
                        borderTopLeftRadius: '8px',
                        justifyContent: 'center',
                        flexGrow: 0
                      }}
                    >
                      <Checkbox
                        sx={{
                          width: '42px',
                          display: 'flex',
                          justifyContent: 'center',
                        }}
                        onClick={() => {
                          if (headerChecked) {
                            setCheckedIdList([]);
                          }
                          else {
                            setCheckedIdList(historyEntries.map(entry => entry.id));
                          }
                        }}
                        checked={headerChecked}
                        indeterminate={headerIndeterminate}
                      />
                    </NulHeaderTableCell>
                  </Box>
                  <Box sx={{ display: 'flex', flexDirection: 'row', flexGrow: 1, position: 'relative', height: '100%', paddingRight: '6px' }}>
                    <NulHeaderTableCell sx={{ width: '10%' }}>
                      ID
                    </NulHeaderTableCell>
                    <NulHeaderTableCell sx={{ width: '25%' }}>
                      Time
                    </NulHeaderTableCell>
                    <NulHeaderTableCell sx={{ width: '30%' }}>
                      Hash
                    </NulHeaderTableCell>
                    <NulHeaderTableCell sx={{ width: '15%' }}>
                      Result
                    </NulHeaderTableCell>
                    <NulHeaderTableCell sx={{ width: '20%' }}>
                      Operations
                    </NulHeaderTableCell>
                  </Box>
                </TableRow>
              </TableHead>
              <TableBody
                sx={{
                  minHeight: '390px', maxHeight: '390px', display: 'block', overflowY: 'auto'
                }}
              >
                {filteredHistoryEntries.map(row => {
                  const checkedIndex: number = checkedIdList.indexOf(row.id);
                  return (
                    <TableRow
                      key={row.id}
                      sx={{
                        width: '100%',
                        display: 'flex',
                        alignItems: 'center',
                        height: '42px'
                      }}
                    >
                      <Box sx={{ height: '100%' }}>
                        <NulTableCell sx={{ width: '62px', justifyContent: 'center', flexGrow: 0 }}>
                          <Checkbox
                            sx={{
                              width: '42px',
                              display: 'flex',
                              justifyContent: 'center',
                            }}
                            checked={checkedIndex !== -1}
                            onChange={(event, checked) => {
                              if (checked) {
                                if (checkedIndex === -1) {
                                  setCheckedIdList([...checkedIdList, row.id]);
                                }
                              }
                              else {
                                if (checkedIndex !== -1) {
                                  setCheckedIdList(removeElementFromArray(checkedIdList, checkedIndex));
                                }
                              }
                            }}
                          />
                        </NulTableCell>
                      </Box>
                      <Box sx={{ display: 'flex', flexDirection: 'row', flexGrow: 1, position: 'relative', height: '100%' }}>
                        <NulTableCell sx={{ width: '10%', display: 'flex' }}>
                          {row.id}
                        </NulTableCell>
                        <NulTableCell sx={{ width: '25%', display: 'flex' }}>
                          {moment(row.time, true).format('YYYY-MM-DD HH:mm:ss')}
                        </NulTableCell>
                        <NulTableCell sx={{ width: '30%', display: 'flex' }}>
                          <Box sx={{ margin: '0px 25px 0px 0px', textOverflow: 'ellipsis', overflow: 'hidden', whiteSpace: 'nowrap' }}>
                            {row.hash}
                          </Box>
                        </NulTableCell>
                        <NulTableCell sx={{ width: '15%', display: 'flex' }}>
                          {transformAnalyzeResult(row.result)}
                        </NulTableCell>
                        <NulTableCell sx={{ width: '20%', display: 'flex' }}>
                          <IconButton onClick={() => { handleViewHistory(row); }}>
                            <VisibilityIcon />
                          </IconButton>
                          <IconButton onClick={() => { handleDownload(row); }}>
                            <DownloadIcon />
                          </IconButton>
                        </NulTableCell>
                      </Box>
                    </TableRow>
                  );
                })}
              </TableBody>
              <TableFooter
                sx={{
                  minHeight: '34px',
                  maxHeight: '44px',
                  display: 'flex',
                  backgroundColor: '#F1F3F5',
                  borderRadius: '0px 0px 8px 8px',
                }}
              >
                <Box sx={{
                  marginLeft: '20px', fontFamily: 'Inter', fontSize: '14px',
                  paddingTop: '10px', paddingBottom: '10px',
                  color: 'rgb(89, 106, 124)'
                }}>
                  Entry Count: {filteredHistoryEntries.length}
                </Box>
              </TableFooter>
            </Table>
          </TableContainer>
        </Box>
      </Box>
      <AlertBox
        open={openAlert}
        title='Result'
        message={result}
        autoHideDuration={4000}
        onClose={() => {
          setOpenAlert(false);
          dispatch(analyzeActions.clearResult());
        }}
      />
      <AnalyzeResult
        open={resultOpen}
        result={result}
        onClose={() => {
          setResultOpen(false);
          dispatch(analyzeActions.clearResult());
        }}
        dicomFile={file}
      />
      <AnalyzeHistory
        open={detailLoaded}
        content={detail}
        onClose={() => {
          dispatch(selectHistoryActions.clearDetail());
        }}
      />
      <SwitchModelDialog
        open={openSwitchModel}
        onClose={() => { setOpenSwitchModel(false); }}
        models={models}
        onChange={(selectedId) => { dispatch(analyzeActions.updateSelectedModelId({ id: selectedId })); }}
        selectedId={selectedModelId}
      />
    </>
  );
}

export default AnalyzeImage;